package com.alex.operateionLog.aop;

import java.util.Collection;
import java.util.Iterator;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.alex.operateionLog.annotation.Log;
import com.alex.operateionLog.domain.OperationLog;
import com.alex.operateionLog.manager.OperationManager;

@Service
@Aspect
public class LogAspect {
	
	private final static Logger log = LoggerFactory.getLogger(LogAspect.class);
	
	@Autowired
	private OperationManager logManager;
	
	 //标注该方法体为后置通知，当目标方法执行成功后执行该方法体   
    @AfterReturning(value="execution(* com.alex..*(..)) && @annotation(rl)")   
    public void addLogSuccess(JoinPoint jp, Log rl) throws Exception{   
    	
    	log.info("---------addLogSuccess-----------");
    	
        Object[] parames = jp.getArgs();//获取目标方法体参数   
        String params = parseParames(parames); //解析目标方法体的参数   
        String className = jp.getTarget().getClass().toString();//获取目标类名   
        className = className.substring(className.indexOf("com"));   
        String signature = jp.getSignature().toString();//获取目标方法签名   
        String methodName = signature.substring(signature.lastIndexOf(".")+1, signature.indexOf("("));   
        String modelName = getModelName(className); //根据类名获取所属的模块   
        
        OperationLog log = new OperationLog();
        log.setInfo(rl.description());
        
        logManager.saveLog(log);   
    }   
    
    //标注该方法体为异常通知，当目标方法出现异常时，执行该方法体
    @AfterThrowing(pointcut="execution(* com.alex..*(..)) && @annotation(rl)", throwing="ex")
    public void addLog(JoinPoint jp, Log rl, Exception ex){
    	
    	log.info("---------addLog-----------");
    	
        Object[] parames = jp.getArgs();
        String params = parseParames(parames);
        String className = jp.getTarget().getClass().toString();
        className = className.substring(className.indexOf("com"));
        String signature = jp.getSignature().toString();
        String methodName = signature.substring(signature.lastIndexOf(".")+1, signature.indexOf("("));
        String modelName = getModelName(className);
        
        OperationLog log = new OperationLog();
        log.setInfo(rl.description());
        
        logManager.saveLog(log);   
    }
    
    /**  
     * 解析方法参数  
     * @param parames 方法参数  
     * @return 解析后的方法参数  
     */  
    private String parseParames(Object[] parames) {   
        StringBuffer sb = new StringBuffer();   
        for(int i=0; i<parames.length; i++){   
            if(parames[i] instanceof Object[] || parames[i] instanceof Collection){   
                JSONArray json = JSONArray.fromObject(parames[i]);   
                if(i==parames.length-1){   
                    sb.append(json.toString());   
                }else{   
                    sb.append(json.toString() + ",");   
                }   
            }else{   
                JSONObject json = JSONObject.fromObject(parames[i]);   
                if(i==parames.length-1){   
                    sb.append(json.toString());   
                }else{   
                    sb.append(json.toString() + ",");   
                }   
            }   
        }   
        String params = sb.toString();   
        params = params.replaceAll("(\"\\w+\":\"\",)", "");   
        params = params.replaceAll("(,\"\\w+\":\"\")", "");   
        return params;   
    }
    
    /**
     * 根据包名查询检索其所属的模块
     * @param packageName 包名
     * @return 模块名称
     */
    private String getModelName(String packageName){
            /*String modelName = "";
            SAXReader reader = new SAXReader();
            try {
                    //读取project.xml模块信息描述xml文档
                    File proj = ResourceUtils.getFile("classpath:project.xml");
                    Document doc = reader.read(proj);
                    //获取文档根节点
                    Element root = doc.getRootElement();
                    //查询模块名称
                    modelName = searchModelName(root, packageName);
            } catch (Exception e) {
                    e.printStackTrace();
            }*/
            return "abc";
    }
    
    /**
     * 采用递归方式根据包名逐级检索所属模块
     * @param element 元素节点
     * @param packageName 包名
     * @return 模块名称
     */
    private String searchModelName(Element element, String packageName){
            String modelName = searchModelNodes(element, packageName);
            //若将包名解析到最后的根目录后仍未检索到模块名称，则返回空
            if(packageName.lastIndexOf(".")==-1){
                    return modelName;
            }
            //逐级检索模块名称
            if(modelName.equals("")){
                    packageName = packageName.substring(0, packageName.lastIndexOf("."));
                    modelName = searchModelName(element, packageName);
            }
            return modelName;
    }
    
    /**
     * 根据xml文档逐个节点检索模块名称
     * @param element 节点元素
     * @param packageName 包名
     * @return 模块名称
     */
    @SuppressWarnings("unchecked")
    private String searchModelNodes(Element element, String packageName){
        String modelName = "";
        Element modules = element.element("modules");
        Iterator it = modules.elementIterator();
        if(!it.hasNext()){
                return modelName;
        }
        while (it.hasNext()) {
            Element model = (Element) it.next();
            String pack = model.attributeValue("packageName");
            String name = model.elementText("moduleCHPath");
            if(packageName.equals(pack)){
                    modelName = name;
                    return modelName;
            }
            if(modelName!=null && !modelName.equals("")){
                    break;
            }
            modelName = searchModelNodes(model, packageName);
        }
        
        return modelName;
    }
    
}
